`use strict`

const fs = require('fs');
const puppeteer = require('puppeteer');
const yargs = require('yargs')
          .option('u', {alias: 'url', describe: 'AMC Page URL', type: 'string'})
          .help('h').alias('h', 'help');
const args = yargs.argv;

const doExtract = (doc) => {
  const removeComments = (ele) => {
    for (let i = ele.childNodes.length-1; i >= 0; i--) {
        let node = ele.childNodes[i];
        if(node.nodeType === Node.COMMENT_NODE) {
            node.remove();
        } else {
            removeComments(node);
        }
    }
  };

  const removeEmptyTextNodes = (ele) => {
    for (let i = ele.childNodes.length-1; i >= 0; i--) {
        let node = ele.childNodes[i];
        if(node.nodeType === Node.TEXT_NODE) {
            if (node.textContent.trim().length == 0)
                node.remove();
        } else {
            removeEmptyTextNodes(node);
        }
    }
  };

  removeComments(doc.documentElement);
  removeEmptyTextNodes(doc.documentElement);
  const tags = ['head', 'script', 'noscript', 'link', 'applet', 'base', 'basefont', 'bgsound', 'button', 'embed', 'frame', 'frameset', 'iframe', 'input', 'isindex', 'label', 'marquee', 'menu', 'object', 'optgroup', 'option', 'param', 'select', 'style', 'textarea', 'table'];
  for (let tag of tags)
    doc.documentElement.querySelectorAll(tag).forEach(ele => ele.remove());

  const attrs = ['#header-wrapper', '#side-column-wrapper', '#toc', '#main-footer', '#small-footer-wrapper', '#login-form', '#print-footer', '#mw-normal-catlinks', '#See_Also', '.printfooter', 'a'];
  for (let attr of attrs)
    doc.documentElement.querySelectorAll(attr).forEach(ele => ele.remove());

  doc.documentElement.querySelectorAll('p').forEach(ele => {
    if (ele.textContent.indexOf('The problems on this page') == 0)
      ele.remove();
  });
  return doc.documentElement.innerHTML;
};

const extractPage = async (page) => {
  const docHandle = await page.evaluateHandle(() => document);
  const result = await page.evaluate(doExtract, docHandle);
  await docHandle.dispose();
  return result;
};

const downloadPage = async (page, url, solution) => {
  let parts = url.split('/');
  parts[parts.length-1] = parts[parts.length-1].replace(/&redirect=no/, '');
  let name = solution ? parts[parts.length-2].replace(/Problems/, 'Solution') + parts[parts.length-1].replace(/Problem_/, '') : parts[parts.length-1];
  let filename = `./output/${name}.pdf`;
  if (fs.existsSync(filename)) {
    console.log(`${new Date().toLocaleString()} downloading page: ${url} ignored cause' ${filename} exists`);
    return true;
  }

  console.log(`${new Date().toLocaleString()} before downloading page: ${url}`);
  try {
   await page.goto(url, {timeout: 0, waitUntil: 'networkidle0'});
  } catch (err) {
    console.log(`${new Date().toLocaleString()} err accessing ${url}, err: ${err}`);
    return false;
  }

  console.log(`${new Date().toLocaleString()} page done: ${url}`);
  const result = await extractPage(page);
  try {
    await page.setContent(result, {timeout: 60000});
  } catch (err) {
    console.log(`${new Date().toLocaleString()} err setContent ${url}, err: ${err}`);
    return false;
  }
  await page.pdf({path: `${filename}`, width: 960, height: 1280, margin: {top: 10, bottom: 10, left: 15, right: 15}});
  // fs.writeFileSync(`./output/${name}.html`, result);
  return true;
};

const downloadPages = async (page, url) => {
  let result = await downloadPage(page, url + '_Problems', false);
  if (!result)
    return;

  await page.waitFor(3000);
  result = await downloadPage(page, url + '_Answer_Key', false);
  if (!result)
    return;

  let total = url.indexOf("_AIME_") == -1 ? 25 : 15;
  for (let i = 1; i <= total; i++) {
    await page.waitFor(3000);
    let url_sol = url + '_Problems/Problem_' + i;
    await downloadPage(page, url_sol, true);
  }
};

if (args.url == undefined) {
  yargs.showHelp();
} else {
  puppeteer.launch().then(async browser => {
    const page = await browser.newPage();
    await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36');
    await page.setViewport({width: 1440, height: 2560});
    page.on('console', msg => {
      if (msg.text().indexOf('JQMIGRATE:') == -1)
        console.log(msg.text());
    });
    await downloadPages(page, args.url);
    await browser.close();
  });
}
